﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;

namespace AzukiMap.DataSource
{
    public class VirtualEarthTiles : TileSource
    {
        const int NUM_OF_LAYERS = 4;

        List<string> _currentBaseUris;
        List<string> _aerialBaseUris;
        List<string> _roadBaseUris;
        List<string> _hybridBaseUris;
        List<string> _trafficBaseUris;
        Dictionary<double, int> _levelsOfDetail;
        Dictionary<VirtualEarthLayerType, string> _tilePrefixes;
        Dictionary<VirtualEarthLayerType, string> _tileExtensions;
        Dictionary<VirtualEarthLayerType, string> _additionalParams;

        VirtualEarthLayerType _tileType;
        Uri _virtualEarthLogo = new Uri("http://maps.live.com/i/bin/20080827.1052/logo_powered_by.png");

        public VirtualEarthLayerType TileType
        {
            set { SetTileType(value); }
            get { return _tileType; }
        }

        public override List<string> BaseUris
        {
            get { return _currentBaseUris; }
        }

        public Dictionary<double, int> LevelsOfDetail
        {
            get { return _levelsOfDetail; }
        }

        public Dictionary<VirtualEarthLayerType, string> TilePrefixes
        {
            get { return _tilePrefixes; }
        }

        public Dictionary<VirtualEarthLayerType, string> TileExtensions
        {
            get { return _tileExtensions; }
        }

        public Dictionary<VirtualEarthLayerType, string> AdditionalParams
        {
            get { return _additionalParams; }
        }

        public VirtualEarthTiles(string name)
            : base(name, 3785, CoordinationUnits.METERS)
        {
            _dpi = 96;
            _tileHeight = 256;
            _tileWidth = 256;

            _aerialBaseUris = new List<string>(NUM_OF_LAYERS);
            _hybridBaseUris = new List<string>(NUM_OF_LAYERS);
            _roadBaseUris = new List<string>(NUM_OF_LAYERS);
            _trafficBaseUris = new List<string>(NUM_OF_LAYERS);
            _tileType = VirtualEarthLayerType.ROAD;
            _levelsOfDetail = new Dictionary<double,int>(NUM_OF_LAYERS);
            _tilePrefixes = new Dictionary<VirtualEarthLayerType, string>(NUM_OF_LAYERS);
            _tileExtensions = new Dictionary<VirtualEarthLayerType, string>(NUM_OF_LAYERS);
            _additionalParams = new Dictionary<VirtualEarthLayerType, string>(NUM_OF_LAYERS);
            _maxExtent = _geoUtil.CreateExtentPolygon(
                -180, 85.05112878, -180, -85.05112878, 180, -85.05112878, 180, 85.05112878);

            SetBaseUris();
            SetLevelsOfDetail();
            SetScales();
            SetTileType(_tileType);
            SetTilePrefixs();
            SetTileExtensions();
            SetAdditionalParams();
        }

        void SetBaseUris()
        {
            _aerialBaseUris.Add("http://a0.ortho.tiles.virtualearth.net/tiles/");
            _aerialBaseUris.Add("http://a1.ortho.tiles.virtualearth.net/tiles/");
            _aerialBaseUris.Add("http://a2.ortho.tiles.virtualearth.net/tiles/");
            _aerialBaseUris.Add("http://a3.ortho.tiles.virtualearth.net/tiles/");

            _roadBaseUris.Add("http://r0.ortho.tiles.virtualearth.net/tiles/");
            _roadBaseUris.Add("http://r1.ortho.tiles.virtualearth.net/tiles/");
            _roadBaseUris.Add("http://r2.ortho.tiles.virtualearth.net/tiles/");
            _roadBaseUris.Add("http://r3.ortho.tiles.virtualearth.net/tiles/");

            _hybridBaseUris.Add("http://h0.ortho.tiles.virtualearth.net/tiles/");
            _hybridBaseUris.Add("http://h1.ortho.tiles.virtualearth.net/tiles/");
            _hybridBaseUris.Add("http://h2.ortho.tiles.virtualearth.net/tiles/");
            _hybridBaseUris.Add("http://h3.ortho.tiles.virtualearth.net/tiles/");

            _trafficBaseUris.Add("http://t0.traffic.virtualearth.net/Flow/");
            _trafficBaseUris.Add("http://t1.traffic.virtualearth.net/Flow/");
            _trafficBaseUris.Add("http://t2.traffic.virtualearth.net/Flow/");
            _trafficBaseUris.Add("http://t3.traffic.virtualearth.net/Flow/");
        }

        void SetLevelsOfDetail()
        {
            _levelsOfDetail.Add(295829355.5,1);
            _levelsOfDetail.Add(147914677.7,2);
            _levelsOfDetail.Add(73957338.86,3);
            _levelsOfDetail.Add(36978669.43,4);
            _levelsOfDetail.Add(18489334.72,5);
            _levelsOfDetail.Add(9244667.36,6);
            _levelsOfDetail.Add(4622333.68,7);
            _levelsOfDetail.Add(2311166.84,8);
            _levelsOfDetail.Add(1155583.42,9);
            _levelsOfDetail.Add(577791.71,10);
            _levelsOfDetail.Add(288895.85,11);
            _levelsOfDetail.Add(144447.93,12);
            _levelsOfDetail.Add(72223.96,13);
            _levelsOfDetail.Add(36111.98,14);
            _levelsOfDetail.Add(18055.99,15);
            _levelsOfDetail.Add(9028,16);
            _levelsOfDetail.Add(4514,17);
            _levelsOfDetail.Add(2257,18);
            _levelsOfDetail.Add(1128.5,19);
            _levelsOfDetail.Add(564.25,20);
            _levelsOfDetail.Add(282.12,21);
            _levelsOfDetail.Add(141.06,22);
            _levelsOfDetail.Add(70.53,23);
        }

        void SetScales()
        {
            foreach (KeyValuePair<double, int> level in _levelsOfDetail)
            {
                _scales.Add(level.Key);
            }
            _scales.Sort();
        }

        void SetTilePrefixs()
        {
            _tilePrefixes.Add(VirtualEarthLayerType.AERIAL, "a");
            _tilePrefixes.Add(VirtualEarthLayerType.HYBRID, "h");
            _tilePrefixes.Add(VirtualEarthLayerType.ROAD, "r");
            _tilePrefixes.Add(VirtualEarthLayerType.TRAFFIC, "t");
        }

        void SetTileExtensions()
        {
            _tileExtensions.Add(VirtualEarthLayerType.AERIAL, ".jpeg");
            _tileExtensions.Add(VirtualEarthLayerType.HYBRID, ".jpeg");
            _tileExtensions.Add(VirtualEarthLayerType.ROAD, ".png");
            _tileExtensions.Add(VirtualEarthLayerType.TRAFFIC, ".png");
        }

        void SetAdditionalParams()
        {
            _additionalParams.Add(VirtualEarthLayerType.AERIAL, "?g=203");
            _additionalParams.Add(VirtualEarthLayerType.HYBRID, "?g=203");
            _additionalParams.Add(VirtualEarthLayerType.ROAD, "?g=203");
            _additionalParams.Add(VirtualEarthLayerType.TRAFFIC, "");
        }

        void SetTileType(VirtualEarthLayerType tileType)
        {
            switch (tileType)
            {
                case VirtualEarthLayerType.AERIAL:
                    _tileType = tileType;
                    _currentBaseUris = _aerialBaseUris;
                    break;
                case VirtualEarthLayerType.HYBRID:
                    _tileType = tileType;
                    _currentBaseUris = _hybridBaseUris;
                    break;
                case VirtualEarthLayerType.ROAD:
                    _tileType = tileType;
                    _currentBaseUris = _roadBaseUris;
                    break;
                case VirtualEarthLayerType.TRAFFIC:
                    _tileType = tileType;
                    _currentBaseUris = _trafficBaseUris;
                    break;
                default:
                    // do nothing.
                    break;
            }
        }
    }

    public enum VirtualEarthLayerType
    {
        AERIAL,
        ROAD,
        HYBRID,
        TRAFFIC
    }
}
